#include "Task.hpp"
const int processNum = 10;
const int taskNum = 8;
const int N = 5;

// 先描述
struct Channal
{
    Channal(int cmdFd, pid_t slaverId, const string &name)
        : _cmdFd(cmdFd), _slaverId(slaverId), _name(name)
    {
    }
    int _cmdFd;      // 发送任务的文件描述符
    pid_t _slaverId; // 子进程的pid
    string _name;    // 子进程的名字,方便我们打印日志
};
// 再组织
vector<Channal> channals;
vector<task_t> tasks;

void Slaver(int rfd)
{
    while(true) {
        int cmdCode = 0;
        // 由于做了dup2,所以可以直接从0里读, 规定一次读4字节
        int n = read(0, &cmdCode, sizeof(int));
        if(n == sizeof(int)) {
            // 执行cmd对应的任务列表
            cout<<"child say@ "<< getpid() << " has been received" <<" cmdCode:" << cmdCode<< endl;
            if(cmdCode >= 0 && cmdCode < taskNum) tasks[cmdCode]();
        } 
        else if(n == 0) break;
        sleep(1);
    }
}

void PrintInfo()
{
    for (const auto &it : channals) {
        cout << it._cmdFd << " " << it._slaverId << " " << it._name << endl;
    }
}

void InitProcessPool()
{
    for (int i = 0; i < processNum; ++i) {
        // 创建管道
        int pipeFd[2];
        int n = pipe(pipeFd);
        assert(!(n==-1));

        pid_t id = fork();
        if (id == 0) {
            // child
            close(pipeFd[1]);
            // 关闭标准输入,用pipeFd[0]替换
            dup2(pipeFd[0], 0);
            Slaver(pipeFd[0]);
            cout<<"process " << getpid() << " quit" << endl;
            exit(0);
        }
        // father
        close(pipeFd[0]);
        string name = "process-" + to_string(i);
        channals.push_back(Channal(pipeFd[1], id, name));
    }
}

// 随机选择进程
void CtrlSlavers1()
{
    for(int i = 1; i <= N; ++i) {
         // a.选择任务
        int cmdCode = rand() % taskNum;
        // b.选择进程
        int processPos = rand() % processNum;
        // c.发送任务
        cout << "father say@ cmdCode " << cmdCode << " has been send to " << 
        channals[processPos]._name << " pid is " << channals[processPos]._slaverId << endl;
        write(channals[processPos]._cmdFd, &cmdCode, sizeof(int));
        sleep(1);
    }
}

// 轮询选择进程
void CtrlSlavers2()
{
    // a. 选择进程
    int which = 0;
    for(int i = 1; i <= N; ++i) {
         // b.选择任务
        int cmdCode = rand() % taskNum;
        // c.发送任务
        cout << "father say@ cmdCode " << cmdCode << " has been send to " << 
        channals[which]._name << " pid is " << channals[which]._slaverId << endl;
        write(channals[which]._cmdFd, &cmdCode, sizeof(int));
        which++;
        which %= processNum;
        sleep(1);
    }
}

void QuitProcess()
{
    // 关闭写端
    for(const auto& it : channals)  close(it._cmdFd);
    sleep(5);
    for(const auto& it : channals) {
        // wait子进程
        waitpid(it._slaverId, nullptr, 0);
    }
    sleep(5);
}
    

/*
我们想让子进程读,父进程写
*/
int main()
{
    srand(time(nullptr));
    LoadTasks(&tasks);
    // 1.初始化
    InitProcessPool();
    // PrintInfo();
    // 2.开始控制子进程
    CtrlSlavers2();
    // 3.清理收尾
    QuitProcess();
    return 0;
}